package com.elitesland.core.base.param;

import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.elitesland.core.base.ApiCode;
import com.elitesland.core.exception.BusinessException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.val;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 可排序查询参数对象
 *
 * @author Mir
 * @date 2019-08-04
 */
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("可排序查询参数对象")
public abstract class AbstractOrderQueryParam extends QueryParam {
    private static final long serialVersionUID = 57714391204790143L;

    private static final String DEFAULT_DIRECTION_COLUMN = "createTime";

    @ApiModelProperty(value = "排序")
    private List<OrderItem> orders;

    public List<OrderItem> getOrders() {
        return orders;
    }

    public void setOrders(List<OrderItem> orders) {
        this.orders = orders;
    }

    public void defaultOrder(OrderItem orderItem) {
        this.defaultOrders(Collections.singletonList(orderItem));
    }

    public void defaultOrders(List<OrderItem> orderItems) {
        if (CollectionUtils.isEmpty(orderItems)) {
            return;
        }
        this.orders = orderItems;
    }

    @JsonIgnore
    public PageRequest getPageRequest() {
        if (CollectionUtils.isEmpty(orders)) {
            return PageRequest.of(getCurrent(), getSize());
        }

        val orderBys = orders.stream().map(o -> new Sort.Order(
                o.isAsc() ? Sort.Direction.ASC : Sort.Direction.DESC,
                StringUtils.isEmpty(o.getColumn()) ? DEFAULT_DIRECTION_COLUMN : o.getColumn()
        )).collect(Collectors.toList());

        // 加入根据ID排序，避免分页时重复数据
        orderBys.add(new Sort.Order(Sort.Direction.ASC, "id"));

        return PageRequest.of(getCurrent(), getSize(), Sort.by(orderBys));
    }

    /**
     * 单表查询,排序方法
     * @param query
     * @param entityPathBase 实体对象
     */
    @JsonIgnore
    public void fillOrders(JPAQuery<?> query, EntityPathBase entityPathBase) {
        val pageRequest = getPageRequest();
        pageRequest.getSort().forEach(s -> {
            val orderbyExpr = new PathBuilder(entityPathBase.getClass(),
                    entityPathBase.getMetadata().getElement().toString());

            query.orderBy(new OrderSpecifier(s.isAscending() ?
                    Order.ASC : Order.DESC, orderbyExpr.get(s.getProperty())));
        });
    }

    /**
     * 多表关联查询，排序方法。要求：排序字段格式需为 “实体对象名称.字段名称”
     * @param query
     */
    @JsonIgnore
    public void fillOrders(JPAQuery<?> query) {
        val pageRequest = getPageRequest();
        pageRequest.getSort().forEach(s -> {
            val sects = s.getProperty().split("\\.");
            if (sects.length > 1) {
                val orderbyExpr = new PathBuilder<>(Object.class, sects[0]);
                query.orderBy(new OrderSpecifier(s.isAscending() ?
                        Order.ASC : Order.DESC, orderbyExpr.get(sects[1])));
            } else {
                throw new BusinessException(ApiCode.PARAMETER_PARSE_EXCEPTION, "排序字段需要指定所属hql的实体对象，对象名称.字段名称");
            }
        });
    }

    @JsonIgnore
    public void setPaging(JPAQuery<?> query) {
        query.offset(getCurrent() * getSize());
        query.limit(getSize());
    }
}
